#include "paneltaskhistory.h"
#include "pm/manager.h"
#include "pmclientdata.h"
#include <boost/foreach.hpp>

#include "res/null16.xpm"
#include "res/finish.xpm"
#include "res/edit_add.xpm"
#include "res/green_check.xpm"
#include "res/warning.xpm"


PanelTaskHistory::PanelTaskHistory(wxWindow* parent)
: PanelTaskHistoryGui(parent)
, m_imgList(16, 16)
{
	m_imgList.Add( wxBitmap(null16_xpm) );
	m_imgList.Add( wxBitmap(finish_xpm) );
	m_imgList.Add( wxBitmap(edit_add_xpm) );
	m_imgList.Add( wxBitmap(green_check_xpm) );
	m_imgList.Add( wxBitmap(warning_xpm) );
	
	m_listHistory->InsertColumn(COL_ALL_UPDATE,    _("Update"));
	m_listHistory->InsertColumn(COL_ALL_NAME,      _("Name"));
	m_listHistory->InsertColumn(COL_ALL_UNIT_COST, _("Unit cost"), wxLIST_FORMAT_RIGHT);
	m_listHistory->InsertColumn(COL_ALL_QUANTITY,  _("Quantity"),  wxLIST_FORMAT_RIGHT);
	m_listHistory->InsertColumn(COL_ALL_COST,      _("Cost"),      wxLIST_FORMAT_RIGHT);
	m_listHistory->InsertColumn(COL_ALL_END_DATE,  _("End"));
	m_listHistory->SetImageList(&m_imgList, wxIMAGE_LIST_SMALL);

	m_listHistoryByDate->InsertColumn(COL_BY_DATE_UPDATE,     _("Update"));
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_NAME,       _("Name"));
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_UNIT_COST,  _("Unit cost"),  wxLIST_FORMAT_RIGHT);
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_QUANTITY,   _("Quantity"),   wxLIST_FORMAT_RIGHT);
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_COST,       _("Cost"),       wxLIST_FORMAT_RIGHT);
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_COST_DONE,  _("Cost done"),  wxLIST_FORMAT_RIGHT);
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_TOTAL_COST, _("Total cost"), wxLIST_FORMAT_RIGHT);
	m_listHistoryByDate->InsertColumn(COL_BY_DATE_END_DATE,   _("End"));
	m_listHistoryByDate->SetImageList(&m_imgList, wxIMAGE_LIST_SMALL);
	
	m_listHistoryByTask->InsertColumn(COL_BY_TASK_UPDATE,    _("Update"));
	m_listHistoryByTask->InsertColumn(COL_BY_TASK_UNIT_COST, _("Unit cost"), wxLIST_FORMAT_RIGHT);
	m_listHistoryByTask->InsertColumn(COL_BY_TASK_QUANTITY,  _("Quantity"),  wxLIST_FORMAT_RIGHT);
	m_listHistoryByTask->InsertColumn(COL_BY_TASK_COST,      _("Cost"),      wxLIST_FORMAT_RIGHT);
	m_listHistoryByTask->InsertColumn(COL_BY_TASK_END_DATE,  _("End"));
	m_listHistoryByTask->SetImageList(&m_imgList, wxIMAGE_LIST_SMALL);
	
	m_listVsInitial->InsertColumn(COL_VS_INITIAL_NAME,   _("Name"));
	m_listVsInitial->InsertColumn(COL_VS_INITIAL_TOTAL,  _("Total"),              wxLIST_FORMAT_RIGHT);
	m_listVsInitial->InsertColumn(COL_VS_INITIAL_INITAL, _("Initial estimation"), wxLIST_FORMAT_RIGHT);
	m_listVsInitial->InsertColumn(COL_VS_INITIAL_TODO,   _("Todo"),               wxLIST_FORMAT_RIGHT);
	m_listVsInitial->InsertColumn(COL_VS_INITIAL_DONE,   _("Done"),               wxLIST_FORMAT_RIGHT);
	m_listVsInitial->SetImageList(&m_imgList, wxIMAGE_LIST_SMALL);
	
	wxDateTime today = wxDateTime::Today();
	m_choiceMonth->SetSelection(today.GetMonth());
	m_spinYear->SetValue(today.GetYear());
	
	wxTheApp->Connect(pmEVT_CONNECT_EVENTS, wxCommandEventHandler(PanelTaskHistory::OnConnectPmEvents), NULL, this);
	wxTheApp->Connect(pmEVT_PROJECT_LOADED, wxCommandEventHandler(PanelTaskHistory::OnProjectLoaded),   NULL, this);
	ConnectPmEvents();
}

void PanelTaskHistory::ConnectPmEvents()
{
	pmConnect(pmEVT_TASK_ADDED,   pm::Task,   PanelTaskHistory::OnTaskChanged);
	pmConnect(pmEVT_TASK_UPDATED, pm::Task,   PanelTaskHistory::OnTaskChanged);
	pmConnect(pmEVT_TASK_REMOVED, db::ID,     PanelTaskHistory::OnTaskRemoved);
	
	pmConnectNotify(pmEVT_COST_ADDED,   PanelTaskHistory::OnHistoryChanged);
	pmConnectNotify(pmEVT_COST_UPDATED, PanelTaskHistory::OnHistoryChanged);
	pmConnectNotify(pmEVT_COST_REMOVED, PanelTaskHistory::OnHistoryChanged);
}

void PanelTaskHistory::DisconnectPmEvents()
{
	pmDisconnect(pmEVT_TASK_ADDED,   pm::Task,   PanelTaskHistory::OnTaskChanged);
	pmDisconnect(pmEVT_TASK_UPDATED, pm::Task,   PanelTaskHistory::OnTaskChanged);
	pmDisconnect(pmEVT_TASK_REMOVED, db::ID,     PanelTaskHistory::OnTaskRemoved);
	
	pmDisconnectNotify(pmEVT_COST_ADDED,   PanelTaskHistory::OnHistoryChanged);
	pmDisconnectNotify(pmEVT_COST_UPDATED, PanelTaskHistory::OnHistoryChanged);
	pmDisconnectNotify(pmEVT_COST_REMOVED, PanelTaskHistory::OnHistoryChanged);
}

void PanelTaskHistory::ReloadTaskChoice()
{
	db::ID idTask;
	int sel = m_choiceTask->GetSelection();
	if (sel != wxNOT_FOUND) {
		idTask = dynamic_cast<IdClientData*>(m_choiceTask->GetClientObject(m_choiceTask->GetSelection()))->id();
	}
	
	m_choiceTask->Clear();
	pm::GetTasksByProject critTasks(wxGetApp().GetActiveProject());
	pm::select(critTasks);
	BOOST_FOREACH(const pm::Task& task, critTasks.m_result) {
		m_choiceTask->Append(task.name(), new IdClientData(task.id()));
	}
	m_choiceTask->SetSelection(0);
	
	if (idTask.valid()) {
		for (size_t i = 0; i < m_choiceTask->GetCount(); ++i) {
			if (dynamic_cast<IdClientData*>(m_choiceTask->GetClientObject(m_choiceTask->GetSelection()))->id() == idTask()) {
				m_choiceTask->SetSelection(i);
				break;
			}
		}
	}
}

wxDateTime PanelTaskHistory::GetDateByDate() const
{
	wxDateTime::Month month = static_cast<wxDateTime::Month>(m_choiceMonth->GetSelection());
	return wxDateTime(1, month, m_spinYear->GetValue());
}

void PanelTaskHistory::ReloadHistory()
{
	m_listHistory->DeleteAllItems();

	pm::GetTaskHistoryByProject crit(wxGetApp().GetActiveProject());
	pm::select(crit);
	BOOST_FOREACH(const pm::TaskHistory& h, crit.m_result) {
		AddTaskHistory(h);
	}
}

void PanelTaskHistory::AddTaskHistory(const pm::TaskHistory& task)
{
	long item = m_listHistory->InsertItem(m_listHistory->GetItemCount(), wxEmptyString);
	SetTaskHistory(item, task);
}

void PanelTaskHistory::SetTaskHistory(long item, const pm::TaskHistory& task)
{
	m_listHistory->SetItem(item, COL_ALL_UPDATE,    task.update_date().FormatISODate());
	m_listHistory->SetItem(item, COL_ALL_NAME,      task.name());
	m_listHistory->SetItem(item, COL_ALL_UNIT_COST, wxString::Format(wxT("%.2f"), task.unit_cost()));
	m_listHistory->SetItem(item, COL_ALL_QUANTITY,  wxString::Format(wxT("%.2f"), task.quantity()));
	m_listHistory->SetItem(item, COL_ALL_COST,      wxString::Format(wxT("%.2f"), task.cost()));
	m_listHistory->SetItem(item, COL_ALL_END_DATE,  task.end_date().FormatISODate());
	
	if (task.finished()) {
		m_listHistory->SetItemImage(item, IMG_FINISH);
	}
	else if (m_listHistory->FindItem(-1, task.id()) == wxNOT_FOUND) {
		m_listHistory->SetItemImage(item, IMG_ADD);
	}
	
	m_listHistory->SetItemData(item, task.id());
}

void PanelTaskHistory::ReloadHistoryByDate()
{
	m_listHistoryByDate->DeleteAllItems();

	wxDateTime date = GetDateByDate();
	date += wxDateSpan::Month() - wxDateSpan::Day();
	pm::GetTaskHistoryByDate crit(wxGetApp().GetActiveProject(), date);
	pm::select(crit);
	BOOST_FOREACH(const pm::TaskAndCost& tc, crit.m_result) {
		AddTaskHistoryByDate(tc);
	}
}

void PanelTaskHistory::AddTaskHistoryByDate(const pm::TaskAndCost& task)
{
	long item = m_listHistoryByDate->InsertItem(m_listHistoryByDate->GetItemCount(), wxEmptyString);
	SetTaskHistoryByDate(item, task);
}

void PanelTaskHistory::SetTaskHistoryByDate(long item, const pm::TaskAndCost& task)
{
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_UPDATE,     task.update_date().FormatISODate());
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_NAME,       task.name());
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_UNIT_COST,  wxString::Format(wxT("%.2f"), task.unit_cost()));
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_QUANTITY,   wxString::Format(wxT("%.2f"), task.quantity()));
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_COST,       wxString::Format(wxT("%.2f"), task.cost()));
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_COST_DONE,  wxString::Format(wxT("%.2f"), task.cost_done()));
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_TOTAL_COST, wxString::Format(wxT("%.2f"), task.total_cost()));
	m_listHistoryByDate->SetItem(item, COL_BY_DATE_END_DATE,   task.end_date().FormatISODate());
	
	m_listHistoryByDate->SetItemData(item, task.id());
	
	if (task.finished()) {
		m_listHistoryByDate->SetItemImage(item, IMG_FINISH);
	}
	wxDateTime curDate = GetDateByDate();
	const wxDateTime& date = task.update_date();
	if (curDate.GetYear() != date.GetYear() || curDate.GetMonth() != date.GetMonth()) {
		m_listHistoryByDate->SetItemTextColour(item, *wxLIGHT_GREY);
	}
}

void PanelTaskHistory::ReloadHistoryByTask()
{
	m_listHistoryByTask->DeleteAllItems();

	db::ID idTask = dynamic_cast<IdClientData*>(m_choiceTask->GetClientObject(m_choiceTask->GetSelection()))->id();
	pm::GetTaskHistoryByTask crit(wxGetApp().GetActiveProject(), idTask);
	pm::select(crit);
	BOOST_FOREACH(const pm::TaskHistory& task, crit.m_result) {
		AddTaskHistoryByTask(task);
	}
}

void PanelTaskHistory::AddTaskHistoryByTask(const pm::TaskHistory& task)
{
	long item = m_listHistoryByTask->InsertItem(m_listHistoryByTask->GetItemCount(), wxEmptyString);
	SetTaskHistoryByTask(item, task);
}

void PanelTaskHistory::SetTaskHistoryByTask(long item, const pm::TaskHistory& task)
{
	m_listHistoryByTask->SetItem(item, COL_BY_TASK_UPDATE,    task.update_date().FormatISODate());
	m_listHistoryByTask->SetItem(item, COL_BY_TASK_UNIT_COST, wxString::Format(wxT("%.2f"), task.unit_cost()));
	m_listHistoryByTask->SetItem(item, COL_BY_TASK_QUANTITY,  wxString::Format(wxT("%.2f"), task.quantity()));
	m_listHistoryByTask->SetItem(item, COL_BY_TASK_COST,      wxString::Format(wxT("%.2f"), task.cost()));
	m_listHistoryByTask->SetItem(item, COL_BY_TASK_END_DATE,  task.end_date().FormatISODate());
	
	if (task.finished()) {
		m_listHistoryByTask->SetItemImage(item, IMG_FINISH);
	}
	else if (m_listHistoryByTask->FindItem(-1, task.id()) == wxNOT_FOUND) {
		m_listHistoryByTask->SetItemImage(item, IMG_ADD);
	}
	
	m_listHistoryByTask->SetItemData(item, task.id());
}

void PanelTaskHistory::ReloadTasksVsInitial()
{
	m_listVsInitial->DeleteAllItems();

	pm::GetTasksVsInitial crit(wxGetApp().GetActiveProject());
	pm::select(crit);
	BOOST_FOREACH(const pm::TaskVsInitial& t, crit.m_result) {
		AddTaskVsInitial(t);
	}
}

void PanelTaskHistory::AddTaskVsInitial(const pm::TaskVsInitial& task)
{
	long item = m_listVsInitial->InsertItem(m_listVsInitial->GetItemCount(), wxEmptyString);
	SetTaskVsInitial(item, task);
}

void PanelTaskHistory::SetTaskVsInitial(long item, const pm::TaskVsInitial& task)
{
	m_listVsInitial->SetItem(item, COL_VS_INITIAL_NAME,   task.name());
	m_listVsInitial->SetItem(item, COL_VS_INITIAL_TOTAL,  wxString::Format(wxT("%.2f"), task.total()));
	m_listVsInitial->SetItem(item, COL_VS_INITIAL_INITAL, wxString::Format(wxT("%.2f"), task.initial()));
	m_listVsInitial->SetItem(item, COL_VS_INITIAL_TODO,   wxString::Format(wxT("%.2f"), task.todo()));
	m_listVsInitial->SetItem(item, COL_VS_INITIAL_DONE,   wxString::Format(wxT("%.2f"), task.done()));
	
	if (task.initial() == 0) {
		m_listVsInitial->SetItemImage(item, IMG_ADD);
	}
	else if (task.difference() < 0) {
		m_listVsInitial->SetItemImage(item, IMG_WARNING);
	}
	else {
		m_listVsInitial->SetItemImage(item, IMG_OK);
	}
	
	m_listVsInitial->SetItemData(item, task.id_task());
}

/**
 * \param event
 */
void PanelTaskHistory::OnConnectPmEvents(wxCommandEvent& event)
{
	event.Skip();
	if (event.GetInt()) {
		ConnectPmEvents();
	}
	else {
		DisconnectPmEvents();
	}
}

void PanelTaskHistory::OnProjectLoaded(wxCommandEvent& event)
{
	event.Skip();
	
	ReloadHistory();
	ReloadHistoryByDate();
	ReloadTaskChoice();
	ReloadHistoryByTask();
	ReloadTasksVsInitial();
}

void PanelTaskHistory::OnTaskChanged(pmEvent<pm::Task>& event)
{
	event.Skip();
	
	ReloadHistory();
	ReloadHistoryByDate();
	ReloadTaskChoice();
	ReloadHistoryByTask();
	ReloadTasksVsInitial();
}

void PanelTaskHistory::OnTaskRemoved(pmEvent<db::ID>& event)
{
	event.Skip();
	
	ReloadHistory();
	ReloadHistoryByDate();
	ReloadTaskChoice();
	ReloadHistoryByTask();
	ReloadTasksVsInitial();
}

void PanelTaskHistory::OnHistoryChanged(wxNotifyEvent& event)
{
	event.Skip();
	
	ReloadHistoryByDate();
	ReloadTasksVsInitial();
}

void PanelTaskHistory::OnDateMinus( wxCommandEvent& WXUNUSED(event) )
{
	wxDateTime date = GetDateByDate();
	date -= wxDateSpan::Month();
	m_choiceMonth->SetSelection(date.GetMonth());
	if (date.GetYear() != m_spinYear->GetValue()) {
		m_spinYear->SetValue(date.GetYear());
	}
	ReloadHistoryByDate();
}

void PanelTaskHistory::OnChoiceMonth( wxCommandEvent& WXUNUSED(event) )
{
	ReloadHistoryByDate();
}

void PanelTaskHistory::OnSpinYear( wxSpinEvent& WXUNUSED(event) )
{
	ReloadHistoryByDate();
}

void PanelTaskHistory::OnDatePlus( wxCommandEvent& WXUNUSED(event) )
{
	wxDateTime date = GetDateByDate();
	date += wxDateSpan::Month();
	m_choiceMonth->SetSelection(date.GetMonth());
	if (date.GetYear() != m_spinYear->GetValue()) {
		m_spinYear->SetValue(date.GetYear());
	}
	ReloadHistoryByDate();
}

void PanelTaskHistory::OnChoiceTask( wxCommandEvent& WXUNUSED(event) )
{
	ReloadHistoryByTask();
}
